﻿using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace OpenWaves.EPiServer.Localization.Model
{
    public class LanguageXmlMerge
    {
        public static XDocument Merge(params XDocument[] documents)
        {
            if (documents.Length == 0)
            {
                return new XDocument();
            }

            var result = new XDocument(documents[0]);

            foreach (var document in documents.Skip(1))
            {
                MergeNode(result.Root, document.Root);
            }

            return result;
        }

        private static string BuildNodeKey(XElement element)
        {
            if (element.Name.LocalName == "language" && element.Parent == element.Document.Root)
            {
                return element.Name.LocalName;
            }

            var nameAttribute = element.Attribute("name");
            return nameAttribute == null
                ? element.Name.LocalName
                : string.Format("{0}[@name={1}]", element.Name, nameAttribute.Value);
        }

        private static void MergeNode(XElement masterElement, XElement slaveElement)
        {
            MergeEqualNodes(masterElement);
            MergeEqualNodes(slaveElement);

            var masterNodeLookup = masterElement.Elements().ToDictionary(BuildNodeKey, e => e);

            foreach (var slaveChild in slaveElement.Elements())
            {
                XElement masterChild;
                var slaveChildKey = BuildNodeKey(slaveChild);
                if (masterNodeLookup.TryGetValue(slaveChildKey, out masterChild) == false)
                {
                    masterElement.Add(slaveChild);
                    masterNodeLookup.Add(slaveChildKey, slaveChild);
                }
                else
                {
                    MergeNode(masterChild, slaveChild);
                }
            }
        }

        private static void MergeEqualNodes(XElement element)
        {
            var childNodeLookup = new Dictionary<string, XElement>();

            foreach (var child in element.Elements().ToList())
            {
                XElement existingChild;
                var key = BuildNodeKey(child);
                if (childNodeLookup.TryGetValue(key, out existingChild))
                {
                    existingChild.Add(child.Elements());
                    MergeEqualNodes(existingChild);
                    child.Remove();
                }
                else
                {
                    childNodeLookup[key] = child;
                    MergeEqualNodes(child);
                }

                
            }
        }
    }
}